package com.xykj.util;

import org.jsoup.Connection;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.springframework.util.StringUtils;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;


/**
 * Jsoup工具类
 */
public class JsoupUtil {
    
    /**
     * 默认User-Agent
     */
    private static final String DEFAULT_USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36";
    
    /**
     * 默认超时时间（毫秒）
     */
    private static final int DEFAULT_TIMEOUT = 30000;
    
    // 随机数生成器
    private static final Random random = new Random();
    
    /**
     * 使用GET方法获取页面文档
     * @param url 网址
     * @return 文档对象
     */
    public static Document getDocument(String url) throws IOException {
        return getDocument(url, DEFAULT_USER_AGENT, null, DEFAULT_TIMEOUT);
    }
    
    /**
     * 使用GET方法获取页面文档
     * @param url 网址
     * @param userAgent 用户代理
     * @param cookies Cookie
     * @param timeout 超时时间
     * @return 文档对象
     */
    public static Document getDocument(String url, String userAgent, Map<String, String> cookies, int timeout) throws IOException {
        if (!StringUtils.hasText(userAgent)) {
            userAgent = DEFAULT_USER_AGENT;
        }
        
        Connection connection = Jsoup.connect(url)
                .userAgent(userAgent)
                .timeout(timeout)
                .ignoreContentType(true)
                .ignoreHttpErrors(true)
                .followRedirects(true) // 跟随重定向
                .maxBodySize(0); // 不限制响应体大小
        
        if (cookies != null && !cookies.isEmpty()) {
            connection.cookies(cookies);
        }
        
        // 添加常用请求头
        connection.header("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8");
        connection.header("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8");
        connection.header("Accept-Encoding", "gzip, deflate, br");
        
        return connection.get();
    }
    
    /**
     * 使用HttpURLConnection获取页面内容（替代方案，可绕过一些网站对Jsoup的限制）
     * @param url 网址
     * @return HTML内容字符串
     */
    public static String getHtmlContentByHttpClient(String url) throws IOException {
        return getHtmlContentByHttpClient(url, getRandomUserAgent(), getCustomHeaders(url), DEFAULT_TIMEOUT);
    }
    
    /**
     * 使用HttpURLConnection获取页面内容（替代方案，可绕过一些网站对Jsoup的限制）
     * @param url 网址
     * @param userAgent 用户代理
     * @param headers 请求头
     * @param timeout 超时时间
     * @return HTML内容字符串
     */
    public static String getHtmlContentByHttpClient(String url, String userAgent, Map<String, String> headers, int timeout) throws IOException {
        if (!StringUtils.hasText(userAgent)) {
            userAgent = DEFAULT_USER_AGENT;
        }
        
        HttpURLConnection connection = null;
        BufferedReader reader = null;
        StringBuilder result = new StringBuilder();
        
        try {
            // 创建URL对象
            URL urlObj = new URL(url);
            
            // 打开连接
            connection = (HttpURLConnection) urlObj.openConnection();
            
            // 设置请求方法
            connection.setRequestMethod("GET");
            
            // 设置超时时间
            connection.setConnectTimeout(timeout);
            connection.setReadTimeout(timeout);
            
            // 设置用户代理
            connection.setRequestProperty("User-Agent", userAgent);
            
            // 接受GZIP编码
            connection.setRequestProperty("Accept-Encoding", "gzip, deflate, br");
            
            // 设置其他请求头
            if (headers != null) {
                for (Map.Entry<String, String> entry : headers.entrySet()) {
                    connection.setRequestProperty(entry.getKey(), entry.getValue());
                }
            }
            
            // 发送请求
            connection.connect();
            
            // 获取响应代码
            int responseCode = connection.getResponseCode();
            if (responseCode == HttpURLConnection.HTTP_OK) {
                // 检查是否是GZIP压缩的内容
                String contentEncoding = connection.getContentEncoding();
                boolean isGzipped = contentEncoding != null && contentEncoding.toLowerCase().contains("gzip");
                
                // 读取响应内容，处理GZIP压缩
                InputStream inputStream;
                if (isGzipped) {
                    inputStream = new java.util.zip.GZIPInputStream(connection.getInputStream());
                } else {
                    inputStream = connection.getInputStream();
                }
                
                // 尝试确定正确的字符集
                String contentType = connection.getContentType();
                String charset = "UTF-8"; // 默认编码
                
                if (contentType != null && contentType.contains("charset=")) {
                    charset = contentType.substring(contentType.indexOf("charset=") + 8);
                    if (charset.contains(";")) {
                        charset = charset.substring(0, charset.indexOf(";"));
                    }
                }
                
                reader = new BufferedReader(new InputStreamReader(inputStream, charset));
                String line;
                while ((line = reader.readLine()) != null) {
                    result.append(line).append("\n");
                }
            } else {
                throw new IOException("HTTP错误码: " + responseCode);
            }
        } finally {
            // 关闭资源
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    // 忽略
                }
            }
            if (connection != null) {
                connection.disconnect();
            }
        }
        
        return result.toString();
    }
    
    /**
     * 从HTML字符串解析为Document对象
     * @param html HTML字符串
     * @param baseUri 基础URI（用于解析相对路径）
     * @return Document对象
     */
    public static Document parseHtmlToDocument(String html, String baseUri) {
        return Jsoup.parse(html, baseUri);
    }
    
    /**
     * 使用POST方法获取页面文档
     * @param url 网址
     * @param data 请求数据
     * @return 文档对象
     */
    public static Document postDocument(String url, Map<String, String> data) throws IOException {
        return postDocument(url, data, DEFAULT_USER_AGENT, null, DEFAULT_TIMEOUT);
    }
    
    /**
     * 使用POST方法获取页面文档
     * @param url 网址
     * @param data 请求数据
     * @param userAgent 用户代理
     * @param cookies Cookie
     * @param timeout 超时时间
     * @return 文档对象
     */
    public static Document postDocument(String url, Map<String, String> data, String userAgent, Map<String, String> cookies, int timeout) throws IOException {
        if (!StringUtils.hasText(userAgent)) {
            userAgent = DEFAULT_USER_AGENT;
        }
        
        Connection connection = Jsoup.connect(url)
                .userAgent(userAgent)
                .timeout(timeout)
                .ignoreContentType(true)
                .ignoreHttpErrors(true)
                .followRedirects(true) // 跟随重定向
                .maxBodySize(0); // 不限制响应体大小
        
        if (cookies != null && !cookies.isEmpty()) {
            connection.cookies(cookies);
        }
        
        if (data != null && !data.isEmpty()) {
            connection.data(data);
        }
        
        // 添加常用请求头
        connection.header("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8");
        connection.header("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8");
        connection.header("Accept-Encoding", "gzip, deflate, br");
        connection.header("Content-Type", "application/x-www-form-urlencoded");
        
        return connection.post();
    }
    
    /**
     * 获取随机的用户代理
     * @return 用户代理字符串
     */
    public static String getRandomUserAgent() {
        // 桌面浏览器 User-Agent
        String[] desktopUserAgents = {
                // Chrome
                "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36",
                "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36",
                "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.75 Safari/537.36",
                "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.83 Safari/537.36",
                // Firefox
                "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:90.0) Gecko/20100101 Firefox/90.0",
                "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:99.0) Gecko/20100101 Firefox/99.0",
                "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:98.0) Gecko/20100101 Firefox/98.0",
                // Safari
                "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.2 Safari/605.1.15",
                "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.4 Safari/605.1.15",
                // Edge
                "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36 Edg/92.0.902.55",
                "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.102 Safari/537.36 Edg/98.0.1108.56",
        };
        
        // 移动设备 User-Agent
        String[] mobileUserAgents = {
                // iPhone/iPad
                "Mozilla/5.0 (iPhone; CPU iPhone OS 15_3_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.3 Mobile/15E148 Safari/604.1",
                "Mozilla/5.0 (iPad; CPU OS 15_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.4 Mobile/15E148 Safari/604.1",
                // Android Chrome
                "Mozilla/5.0 (Linux; Android 12; SM-G998B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.73 Mobile Safari/537.36",
                "Mozilla/5.0 (Linux; Android 11; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.73 Mobile Safari/537.36",
                // Android Firefox
                "Mozilla/5.0 (Android 12; Mobile; rv:98.0) Gecko/98.0 Firefox/98.0",
        };
        
        // 合并所有 User-Agent
        String[] allUserAgents = new String[desktopUserAgents.length + mobileUserAgents.length];
        System.arraycopy(desktopUserAgents, 0, allUserAgents, 0, desktopUserAgents.length);
        System.arraycopy(mobileUserAgents, 0, allUserAgents, desktopUserAgents.length, mobileUserAgents.length);
        
        // 75%的概率使用桌面浏览器UserAgent，25%的概率使用移动设备UserAgent
        if (random.nextInt(100) < 75) {
            return desktopUserAgents[random.nextInt(desktopUserAgents.length)];
        } else {
            return mobileUserAgents[random.nextInt(mobileUserAgents.length)];
        }
    }
    
    /**
     * 获取适用于特定网站的请求头
     * @param url 目标URL
     * @return 请求头映射
     */
    public static Map<String, String> getCustomHeaders(String url) {
        Map<String, String> headers = new HashMap<>();
        
        // 通用请求头
        headers.put("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9");
        headers.put("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8");
        headers.put("Accept-Encoding", "gzip, deflate, br");
        headers.put("Connection", "keep-alive");
        headers.put("Upgrade-Insecure-Requests", "1");
        
        // 针对不同网站的自定义请求头
        if (url.contains("eastmoney.com")) {
            headers.put("Referer", "https://www.eastmoney.com/");
            // 添加常见的东方财富网Cookie
            String sessionId = String.valueOf(System.currentTimeMillis()) + random.nextInt(1000);
            headers.put("Cookie", "em_hq_fls=js; qgqp_b_id=" + random.nextInt(100000000) + 
                        "; HAList=a-sh-603088-%u6613%u7EF4%u79D1%u6280; em-quote-version=topspeed; st_si=" + sessionId);
        } else if (url.contains("sina.com")) {
            headers.put("Referer", "https://finance.sina.com.cn/");
        } else if (url.contains("163.com")) {
            headers.put("Referer", "https://money.163.com/");
        }
        
        return headers;
    }
} 